#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
剪映草稿自动化管理界面
提供可视化的配置管理、服务控制、日志查看等功能
"""

# 修复COM线程冲突：设置COM为多线程模式
import sys
sys.coinit_flags = 0  # COINIT_MULTITHREADED，解决与API服务的COM对象冲突

import os
import time
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import threading
import logging
from datetime import datetime
import webbrowser

# 导入自定义模块
from config_manager import get_config
from service_controller import ServiceController
from log_viewer import LogViewer, LogLevel
from oss_uploader import OSSUploader


class ConfigTab:
    """配置选项卡"""

    def __init__(self, parent, config_manager):
        self.parent = parent
        self.config = config_manager

        self.create_widgets()
        self.load_config()

    def create_widgets(self):
        """创建界面控件"""
        # 主框架
        main_frame = ttk.Frame(self.parent)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 输出路径配置
        path_frame = ttk.LabelFrame(main_frame, text="输出路径配置", padding=10)
        path_frame.pack(fill=tk.X, pady=(0, 10))

        ttk.Label(path_frame, text="默认输出路径:").grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
        self.output_path_var = tk.StringVar()
        path_entry = ttk.Entry(path_frame, textvariable=self.output_path_var, width=50)
        path_entry.grid(row=0, column=1, sticky=tk.EW, padx=(0, 10))

        ttk.Button(path_frame, text="浏览...", command=self.browse_output_path).grid(row=0, column=2)

        path_frame.columnconfigure(1, weight=1)

        # OSS配置
        oss_frame = ttk.LabelFrame(main_frame, text="阿里云OSS配置", padding=10)
        oss_frame.pack(fill=tk.X, pady=(0, 10))

        # OSS启用开关
        self.oss_enabled_var = tk.BooleanVar()
        ttk.Checkbutton(oss_frame, text="启用阿里云OSS自动上传",
                       variable=self.oss_enabled_var,
                       command=self.toggle_oss_controls).grid(row=0, column=0, columnspan=3, sticky=tk.W, pady=(0, 10))

        # OSS配置项
        self.oss_controls = []

        row = 1
        # Access Key ID
        ttk.Label(oss_frame, text="Access Key ID:").grid(row=row, column=0, sticky=tk.W, padx=(0, 10))
        self.access_key_var = tk.StringVar()
        access_key_entry = ttk.Entry(oss_frame, textvariable=self.access_key_var, width=40)
        access_key_entry.grid(row=row, column=1, sticky=tk.EW, padx=(0, 10))
        self.oss_controls.extend([access_key_entry])

        row += 1
        # Access Key Secret
        ttk.Label(oss_frame, text="Access Key Secret:").grid(row=row, column=0, sticky=tk.W, padx=(0, 10))
        self.access_secret_var = tk.StringVar()
        secret_entry = ttk.Entry(oss_frame, textvariable=self.access_secret_var, width=40, show="*")
        secret_entry.grid(row=row, column=1, sticky=tk.EW, padx=(0, 10))
        self.oss_controls.append(secret_entry)

        row += 1
        # Bucket Name
        ttk.Label(oss_frame, text="Bucket名称:").grid(row=row, column=0, sticky=tk.W, padx=(0, 10))
        self.bucket_name_var = tk.StringVar()
        bucket_entry = ttk.Entry(oss_frame, textvariable=self.bucket_name_var, width=40)
        bucket_entry.grid(row=row, column=1, sticky=tk.EW, padx=(0, 10))
        self.oss_controls.append(bucket_entry)

        row += 1
        # Endpoint
        ttk.Label(oss_frame, text="Endpoint:").grid(row=row, column=0, sticky=tk.W, padx=(0, 10))
        self.endpoint_var = tk.StringVar()
        endpoint_entry = ttk.Entry(oss_frame, textvariable=self.endpoint_var, width=40)
        endpoint_entry.grid(row=row, column=1, sticky=tk.EW, padx=(0, 10))
        self.oss_controls.append(endpoint_entry)

        oss_frame.columnconfigure(1, weight=1)

        # 按钮区域
        button_frame = ttk.Frame(oss_frame)
        button_frame.grid(row=row+1, column=0, columnspan=3, pady=(10, 0))

        ttk.Button(button_frame, text="测试OSS连接", command=self.test_oss_connection).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(button_frame, text="保存配置", command=self.save_config).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(button_frame, text="重置为默认", command=self.reset_config).pack(side=tk.LEFT)

        # 服务配置
        service_frame = ttk.LabelFrame(main_frame, text="服务配置", padding=10)
        service_frame.pack(fill=tk.X, pady=(0, 10))

        ttk.Label(service_frame, text="监听地址:").grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
        self.host_var = tk.StringVar()
        ttk.Entry(service_frame, textvariable=self.host_var, width=20).grid(row=0, column=1, sticky=tk.W, padx=(0, 20))

        ttk.Label(service_frame, text="端口:").grid(row=0, column=2, sticky=tk.W, padx=(0, 10))
        self.port_var = tk.StringVar()
        ttk.Entry(service_frame, textvariable=self.port_var, width=10).grid(row=0, column=3, sticky=tk.W)

        service_frame.columnconfigure(4, weight=1)

        # Worker配置
        worker_frame = ttk.LabelFrame(main_frame, text="Worker配置", padding=10)
        worker_frame.pack(fill=tk.X, pady=(0, 10))

        # Worker启用开关
        self.worker_enabled_var = tk.BooleanVar()
        ttk.Checkbutton(worker_frame, text="启用Worker模式（连接远程调度系统）",
                       variable=self.worker_enabled_var,
                       command=self.toggle_worker_controls).grid(row=0, column=0, columnspan=3, sticky=tk.W, pady=(0, 10))

        # Worker配置项
        self.worker_controls = []

        row = 1
        # Worker ID
        ttk.Label(worker_frame, text="Worker ID:").grid(row=row, column=0, sticky=tk.W, padx=(0, 10))
        self.worker_id_var = tk.StringVar()
        worker_id_entry = ttk.Entry(worker_frame, textvariable=self.worker_id_var, width=20)
        worker_id_entry.grid(row=row, column=1, sticky=tk.W, padx=(0, 20))
        self.worker_controls.append(worker_id_entry)

        # Worker名称
        ttk.Label(worker_frame, text="Worker名称:").grid(row=row, column=2, sticky=tk.W, padx=(0, 10))
        self.worker_name_var = tk.StringVar()
        worker_name_entry = ttk.Entry(worker_frame, textvariable=self.worker_name_var, width=25)
        worker_name_entry.grid(row=row, column=3, sticky=tk.W)
        self.worker_controls.append(worker_name_entry)

        row += 1
        # API地址
        ttk.Label(worker_frame, text="调度系统API地址:").grid(row=row, column=0, sticky=tk.W, padx=(0, 10))
        self.worker_api_base_var = tk.StringVar()
        api_base_entry = ttk.Entry(worker_frame, textvariable=self.worker_api_base_var, width=60)
        api_base_entry.grid(row=row, column=1, columnspan=3, sticky=tk.EW, padx=(0, 10))
        self.worker_controls.append(api_base_entry)

        row += 1
        # IP地址
        ttk.Label(worker_frame, text="本机IP地址:").grid(row=row, column=0, sticky=tk.W, padx=(0, 10))
        self.worker_ip_var = tk.StringVar()
        ip_entry = ttk.Entry(worker_frame, textvariable=self.worker_ip_var, width=20)
        ip_entry.grid(row=row, column=1, sticky=tk.W, padx=(0, 20))
        self.worker_controls.append(ip_entry)

        # 主机名
        ttk.Label(worker_frame, text="主机名:").grid(row=row, column=2, sticky=tk.W, padx=(0, 10))
        self.worker_hostname_var = tk.StringVar()
        hostname_entry = ttk.Entry(worker_frame, textvariable=self.worker_hostname_var, width=25)
        hostname_entry.grid(row=row, column=3, sticky=tk.W)
        self.worker_controls.append(hostname_entry)

        row += 1
        # 最大并发任务数
        ttk.Label(worker_frame, text="最大并发任务数:").grid(row=row, column=0, sticky=tk.W, padx=(0, 10))
        self.worker_max_tasks_var = tk.StringVar()
        max_tasks_spinbox = ttk.Spinbox(worker_frame, textvariable=self.worker_max_tasks_var,
                                       from_=1, to=20, width=10)
        max_tasks_spinbox.grid(row=row, column=1, sticky=tk.W, padx=(0, 20))
        self.worker_controls.append(max_tasks_spinbox)

        # 心跳间隔
        ttk.Label(worker_frame, text="心跳间隔(秒):").grid(row=row, column=2, sticky=tk.W, padx=(0, 10))
        self.worker_heartbeat_var = tk.StringVar()
        heartbeat_spinbox = ttk.Spinbox(worker_frame, textvariable=self.worker_heartbeat_var,
                                       from_=10, to=300, width=10)
        heartbeat_spinbox.grid(row=row, column=3, sticky=tk.W)
        self.worker_controls.append(heartbeat_spinbox)

        worker_frame.columnconfigure(4, weight=1)

        # Worker按钮区域
        worker_button_frame = ttk.Frame(worker_frame)
        worker_button_frame.grid(row=row+1, column=0, columnspan=4, pady=(10, 0))

        ttk.Button(worker_button_frame, text="测试连接", command=self.test_worker_connection).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(worker_button_frame, text="自动填充", command=self.auto_fill_worker_info).pack(side=tk.LEFT)

    def browse_output_path(self):
        """浏览输出路径"""
        directory = filedialog.askdirectory(title="选择默认输出路径")
        if directory:
            self.output_path_var.set(directory)

    def toggle_oss_controls(self):
        """切换OSS控件状态"""
        enabled = self.oss_enabled_var.get()
        state = tk.NORMAL if enabled else tk.DISABLED

        for control in self.oss_controls:
            control.configure(state=state)

    def test_oss_connection(self):
        """测试OSS连接"""
        if not self.oss_enabled_var.get():
            messagebox.showwarning("提示", "请先启用OSS配置")
            return

        # 获取当前配置
        oss_config = {
            "access_key_id": self.access_key_var.get(),
            "access_key_secret": self.access_secret_var.get(),
            "bucket_name": self.bucket_name_var.get(),
            "endpoint": self.endpoint_var.get(),
            "enabled": True
        }

        # 验证配置
        required_fields = ['access_key_id', 'access_key_secret', 'bucket_name', 'endpoint']
        for field in required_fields:
            if not oss_config.get(field):
                messagebox.showerror("错误", f"请填写{field}")
                return

        try:
            # 创建OSS上传器并测试
            uploader = OSSUploader(oss_config)
            result = uploader.test_oss_connection()

            if result["success"]:
                messagebox.showinfo("成功", f"OSS连接测试成功!\n{result['message']}")
            else:
                messagebox.showerror("失败", f"OSS连接测试失败:\n{result['message']}")

        except Exception as e:
            messagebox.showerror("错误", f"测试OSS连接时发生错误:\n{str(e)}")

    def toggle_worker_controls(self):
        """切换Worker控件状态"""
        enabled = self.worker_enabled_var.get()
        state = tk.NORMAL if enabled else tk.DISABLED

        for control in self.worker_controls:
            control.configure(state=state)

    def test_worker_connection(self):
        """测试Worker连接"""
        if not self.worker_enabled_var.get():
            messagebox.showwarning("提示", "请先启用Worker模式")
            return

        # 获取当前配置
        worker_config = {
            "enabled": True,
            "id": self.worker_id_var.get(),
            "workerName": self.worker_name_var.get(),
            "api_base": self.worker_api_base_var.get(),
            "ipAddress": self.worker_ip_var.get(),
            "hostname": self.worker_hostname_var.get(),
            "maxConcurrentTasks": int(self.worker_max_tasks_var.get()) if self.worker_max_tasks_var.get().isdigit() else 4,
            "heartbeat_interval": int(self.worker_heartbeat_var.get()) if self.worker_heartbeat_var.get().isdigit() else 30
        }

        # 验证配置
        required_fields = ['id', 'workerName', 'api_base']
        for field in required_fields:
            if not worker_config.get(field):
                messagebox.showerror("错误", f"请填写{field}")
                return

        try:
            # 测试网络连接
            import requests
            api_base = worker_config['api_base'].rstrip('/')

            response = requests.get(api_base, timeout=10)
            messagebox.showinfo("成功", f"调度系统连接测试成功!\nHTTP状态: {response.status_code}")

        except requests.exceptions.ConnectionError:
            messagebox.showerror("失败", "无法连接到调度系统\n请检查API地址是否正确")
        except requests.exceptions.Timeout:
            messagebox.showerror("失败", "连接调度系统超时\n请检查网络连接")
        except Exception as e:
            messagebox.showerror("错误", f"测试Worker连接时发生错误:\n{str(e)}")

    def auto_fill_worker_info(self):
        """自动填充Worker信息"""
        try:
            import socket
            import platform
            import uuid

            # 自动获取主机名
            if not self.worker_hostname_var.get():
                hostname = platform.node() or socket.gethostname()
                self.worker_hostname_var.set(hostname)

            # 自动获取IP地址
            if not self.worker_ip_var.get():
                try:
                    # 连接到一个外部地址获取本机IP
                    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
                    s.connect(("8.8.8.8", 80))
                    local_ip = s.getsockname()[0]
                    s.close()
                    self.worker_ip_var.set(local_ip)
                except:
                    self.worker_ip_var.set("127.0.0.1")

            # 生成Worker ID（如果为空）
            if not self.worker_id_var.get():
                worker_id = f"worker_{uuid.uuid4().hex[:8]}"
                self.worker_id_var.set(worker_id)

            # 设置默认Worker名称
            if not self.worker_name_var.get():
                os_name = platform.system()
                self.worker_name_var.set(f"{os_name}-Python-Worker")

            messagebox.showinfo("成功", "Worker信息已自动填充")

        except Exception as e:
            messagebox.showerror("错误", f"自动填充Worker信息时发生错误:\n{str(e)}")

    def save_config(self):
        """保存配置"""
        try:
            # 保存输出路径
            self.config.set_output_path(self.output_path_var.get())

            # 保存OSS配置
            oss_config = {
                "access_key_id": self.access_key_var.get(),
                "access_key_secret": self.access_secret_var.get(),
                "bucket_name": self.bucket_name_var.get(),
                "endpoint": self.endpoint_var.get(),
                "enabled": self.oss_enabled_var.get()
            }
            self.config.set_oss_config(oss_config)

            # 保存服务配置
            service_config = {
                "host": self.host_var.get(),
                "port": int(self.port_var.get()) if self.port_var.get().isdigit() else 5000
            }
            self.config.set_service_config(service_config)

            # 保存Worker配置
            worker_config = {
                "enabled": self.worker_enabled_var.get(),
                "id": self.worker_id_var.get(),
                "workerName": self.worker_name_var.get(),
                "api_base": self.worker_api_base_var.get(),
                "ipAddress": self.worker_ip_var.get(),
                "hostname": self.worker_hostname_var.get(),
                "maxConcurrentTasks": int(self.worker_max_tasks_var.get()) if self.worker_max_tasks_var.get().isdigit() else 4,
                "heartbeat_interval": int(self.worker_heartbeat_var.get()) if self.worker_heartbeat_var.get().isdigit() else 30
            }
            self.config.set_worker_config(worker_config)

            # 保存到文件
            if self.config.save_config():
                messagebox.showinfo("成功", "配置保存成功!")
            else:
                messagebox.showerror("失败", "配置保存失败!")

        except Exception as e:
            messagebox.showerror("错误", f"保存配置时发生错误:\n{str(e)}")

    def reset_config(self):
        """重置配置"""
        if messagebox.askyesno("确认", "确定要重置为默认配置吗？"):
            self.config.reset_to_default()
            self.load_config()
            messagebox.showinfo("成功", "配置已重置为默认值")

    def load_config(self):
        """加载配置"""
        # 加载输出路径
        self.output_path_var.set(self.config.get_output_path())

        # 加载OSS配置
        oss_config = self.config.get_oss_config()
        self.oss_enabled_var.set(oss_config.get('enabled', False))
        self.access_key_var.set(oss_config.get('access_key_id', ''))
        self.access_secret_var.set(oss_config.get('access_key_secret', ''))
        self.bucket_name_var.set(oss_config.get('bucket_name', ''))
        self.endpoint_var.set(oss_config.get('endpoint', 'oss-cn-hangzhou.aliyuncs.com'))

        # 加载服务配置
        service_config = self.config.get_service_config()
        self.host_var.set(service_config.get('host', '0.0.0.0'))
        self.port_var.set(str(service_config.get('port', 5000)))

        # 加载Worker配置
        worker_config = self.config.get_worker_config()
        self.worker_enabled_var.set(worker_config.get('enabled', False))
        self.worker_id_var.set(worker_config.get('id', ''))
        self.worker_name_var.set(worker_config.get('workerName', ''))
        self.worker_api_base_var.set(worker_config.get('api_base', ''))
        self.worker_ip_var.set(worker_config.get('ipAddress', ''))
        self.worker_hostname_var.set(worker_config.get('hostname', ''))
        self.worker_max_tasks_var.set(str(worker_config.get('maxConcurrentTasks', 4)))
        self.worker_heartbeat_var.set(str(worker_config.get('heartbeat_interval', 30)))

        # 更新控件状态
        self.toggle_oss_controls()
        self.toggle_worker_controls()


class ServiceTab:
    """服务选项卡"""

    def __init__(self, parent, config_manager):
        self.parent = parent
        self.config = config_manager
        self.service_controller = ServiceController(config_manager)
        self.logger = logging.getLogger(__name__)

        self.create_widgets()
        self.update_status()

        # 设置状态回调
        self.service_controller.set_status_callback(self.on_status_change)

        # 启动状态更新线程
        self.start_status_update_thread()

        # 初始化Worker状态显示
        self._clear_worker_status_display()

    def create_widgets(self):
        """创建界面控件"""
        # 主框架
        main_frame = ttk.Frame(self.parent)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 服务状态
        status_frame = ttk.LabelFrame(main_frame, text="服务状态", padding=10)
        status_frame.pack(fill=tk.X, pady=(0, 10))

        # 状态指示器
        self.status_label = ttk.Label(status_frame, text="● 未知", font=("Arial", 12, "bold"))
        self.status_label.grid(row=0, column=0, sticky=tk.W, padx=(0, 20))

        self.detail_label = ttk.Label(status_frame, text="检查中...")
        self.detail_label.grid(row=0, column=1, sticky=tk.W)

        status_frame.columnconfigure(2, weight=1)

        # 服务信息
        info_frame = ttk.Frame(status_frame)
        info_frame.grid(row=1, column=0, columnspan=3, sticky=tk.EW, pady=(10, 0))

        ttk.Label(info_frame, text="服务地址:").grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
        self.address_label = ttk.Label(info_frame, text="-")
        self.address_label.grid(row=0, column=1, sticky=tk.W, padx=(0, 20))

        ttk.Label(info_frame, text="进程ID:").grid(row=0, column=2, sticky=tk.W, padx=(0, 10))
        self.pid_label = ttk.Label(info_frame, text="-")
        self.pid_label.grid(row=0, column=3, sticky=tk.W, padx=(0, 20))

        ttk.Label(info_frame, text="运行时间:").grid(row=0, column=4, sticky=tk.W, padx=(0, 10))
        self.uptime_label = ttk.Label(info_frame, text="-")
        self.uptime_label.grid(row=0, column=5, sticky=tk.W)

        info_frame.columnconfigure(6, weight=1)

        # 控制按钮
        control_frame = ttk.LabelFrame(main_frame, text="服务控制", padding=10)
        control_frame.pack(fill=tk.X, pady=(0, 10))

        self.start_button = ttk.Button(control_frame, text="启动服务", command=self.start_service)
        self.start_button.pack(side=tk.LEFT, padx=(0, 10))

        self.stop_button = ttk.Button(control_frame, text="停止服务", command=self.stop_service)
        self.stop_button.pack(side=tk.LEFT, padx=(0, 10))

        self.restart_button = ttk.Button(control_frame, text="重启服务", command=self.restart_service)
        self.restart_button.pack(side=tk.LEFT, padx=(0, 20))

        ttk.Button(control_frame, text="测试连接", command=self.test_connection).pack(side=tk.LEFT, padx=(0, 10))

        # Worker控制
        worker_frame = ttk.LabelFrame(main_frame, text="Worker控制", padding=10)
        worker_frame.pack(fill=tk.X, pady=(0, 10))

        # Worker状态
        worker_status_frame = ttk.Frame(worker_frame)
        worker_status_frame.pack(fill=tk.X, pady=(0, 10))

        self.worker_status_label = ttk.Label(worker_status_frame, text="● Worker未启动", font=("Arial", 11, "bold"))
        self.worker_status_label.pack(side=tk.LEFT, padx=(0, 20))

        self.worker_detail_label = ttk.Label(worker_status_frame, text="")
        self.worker_detail_label.pack(side=tk.LEFT)

        # Worker信息
        worker_info_frame = ttk.Frame(worker_frame)
        worker_info_frame.pack(fill=tk.X, pady=(0, 10))

        ttk.Label(worker_info_frame, text="Worker ID:").grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
        self.worker_id_label = ttk.Label(worker_info_frame, text="-")
        self.worker_id_label.grid(row=0, column=1, sticky=tk.W, padx=(0, 20))

        ttk.Label(worker_info_frame, text="当前任务:").grid(row=0, column=2, sticky=tk.W, padx=(0, 10))
        self.worker_tasks_label = ttk.Label(worker_info_frame, text="-")
        self.worker_tasks_label.grid(row=0, column=3, sticky=tk.W, padx=(0, 20))

        ttk.Label(worker_info_frame, text="调度系统:").grid(row=0, column=4, sticky=tk.W, padx=(0, 10))
        self.worker_api_label = ttk.Label(worker_info_frame, text="-")
        self.worker_api_label.grid(row=0, column=5, sticky=tk.W)

        worker_info_frame.columnconfigure(6, weight=1)

        # Worker控制按钮
        worker_control_frame = ttk.Frame(worker_frame)
        worker_control_frame.pack(fill=tk.X)

        self.start_worker_button = ttk.Button(worker_control_frame, text="启动Worker", command=self.start_worker)
        self.start_worker_button.pack(side=tk.LEFT, padx=(0, 10))

        self.stop_worker_button = ttk.Button(worker_control_frame, text="停止Worker", command=self.stop_worker)
        self.stop_worker_button.pack(side=tk.LEFT, padx=(0, 10))

        ttk.Button(worker_control_frame, text="Worker状态", command=self.show_worker_status).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(worker_control_frame, text="测试Worker连接", command=self.test_worker_connection).pack(side=tk.LEFT)

        # Worker变量初始化
        self.worker_client = None
        self.worker_thread = None

        # 设置按钮初始状态：启动按钮启用，停止按钮禁用
        self.start_worker_button.configure(state=tk.NORMAL)
        self.stop_worker_button.configure(state=tk.DISABLED)

        # 快速测试
        test_frame = ttk.LabelFrame(main_frame, text="快速测试", padding=10)
        test_frame.pack(fill=tk.X, pady=(0, 10))

        # 任务管理
        self.create_task_management_ui(main_frame)


    def start_service(self):
        """启动服务"""
        def start_in_thread():
            result = self.service_controller.start_service()
            if not result["success"]:
                self.parent.after(0, lambda: messagebox.showerror("启动失败", result["message"]))

        threading.Thread(target=start_in_thread, daemon=True).start()

    def stop_service(self):
        """停止服务"""
        def stop_in_thread():
            result = self.service_controller.stop_service()
            if not result["success"]:
                self.parent.after(0, lambda: messagebox.showerror("停止失败", result["message"]))

        threading.Thread(target=stop_in_thread, daemon=True).start()

    def restart_service(self):
        """重启服务"""
        def restart_in_thread():
            result = self.service_controller.restart_service()
            if not result["success"]:
                self.parent.after(0, lambda: messagebox.showerror("重启失败", result["message"]))

        threading.Thread(target=restart_in_thread, daemon=True).start()

    def test_connection(self):
        """测试连接"""
        def test_in_thread():
            result = self.service_controller.test_service_connection()
            message = f"连接测试: {result['message']}"
            if result.get("response_time"):
                message += f"\n响应时间: {result['response_time']}ms"

            if result["success"]:
                self.parent.after(0, lambda: messagebox.showinfo("连接测试", message))
            else:
                self.parent.after(0, lambda: messagebox.showerror("连接测试", message))

        threading.Thread(target=test_in_thread, daemon=True).start()

    def start_worker(self):
        """启动Worker"""
        if not self.config.is_worker_enabled():
            messagebox.showerror("错误", "Worker功能未启用\n请先在配置页面启用Worker模式")
            return

        if self.worker_client and hasattr(self.worker_client, 'is_running') and self.worker_client.is_running:
            messagebox.showwarning("提示", "Worker已在运行中")
            return

        # 禁用启动按钮，防止重复点击
        self.start_worker_button.configure(state=tk.DISABLED)

        def start_worker_in_thread():
            try:
                # 导入Worker客户端
                from worker_client import WorkerClient

                # 创建Worker客户端
                self.worker_client = WorkerClient(self.config)

                # 启动Worker
                success = self.worker_client.start()

                if success:
                    self.parent.after(0, lambda: self._on_worker_started())
                else:
                    self.parent.after(0, lambda: self._on_worker_start_failed("Worker启动失败"))

            except Exception as e:
                error_msg = f"启动Worker时发生错误:\n{str(e)}"
                self.parent.after(0, lambda: self._on_worker_start_failed(error_msg))

        threading.Thread(target=start_worker_in_thread, daemon=True).start()

    def _on_worker_started(self):
        """Worker启动成功的回调"""
        messagebox.showinfo("成功", "Worker启动成功")
        # 更新按钮状态
        self.start_worker_button.configure(state=tk.DISABLED)
        self.stop_worker_button.configure(state=tk.NORMAL)
        # 启动Worker监控线程
        self.worker_thread = threading.Thread(target=self._worker_monitor_thread, daemon=True)
        self.worker_thread.start()

    def _on_worker_start_failed(self, error_msg):
        """Worker启动失败的回调"""
        messagebox.showerror("失败", error_msg)
        # 恢复按钮状态
        self.start_worker_button.configure(state=tk.NORMAL)
        self.stop_worker_button.configure(state=tk.DISABLED)
        self.worker_client = None

    def stop_worker(self):
        """停止Worker"""
        if not self.worker_client or not hasattr(self.worker_client, 'is_running') or not self.worker_client.is_running:
            messagebox.showwarning("提示", "Worker未在运行")
            return

        # 禁用停止按钮，防止重复点击
        self.stop_worker_button.configure(state=tk.DISABLED)

        def stop_worker_in_thread():
            try:
                self.worker_client.stop()
                self.worker_client = None
                self.parent.after(0, lambda: self._on_worker_stopped())

            except Exception as e:
                error_msg = f"停止Worker时发生错误:\n{str(e)}"
                self.parent.after(0, lambda: self._on_worker_stop_failed(error_msg))

        threading.Thread(target=stop_worker_in_thread, daemon=True).start()

    def _on_worker_stopped(self):
        """Worker停止成功的回调"""
        messagebox.showinfo("成功", "Worker已停止")
        # 更新按钮状态
        self.start_worker_button.configure(state=tk.NORMAL)
        self.stop_worker_button.configure(state=tk.DISABLED)

    def _on_worker_stop_failed(self, error_msg):
        """Worker停止失败的回调"""
        messagebox.showerror("错误", error_msg)
        # 恢复按钮状态
        self.stop_worker_button.configure(state=tk.NORMAL)

    def show_worker_status(self):
        """显示Worker详细状态"""
        if not self.worker_client:
            messagebox.showinfo("Worker状态", "Worker未启动")
            return

        try:
            status = self.worker_client.get_status()

            status_text = []
            status_text.append(f"运行状态: {'运行中' if status.get('is_running') else '未运行'}")
            status_text.append(f"启动时间: {status.get('start_time', '未知')}")

            if status.get('uptime_seconds'):
                uptime = status['uptime_seconds']
                if uptime < 3600:
                    uptime_str = f"{int(uptime // 60)}分钟"
                else:
                    hours = int(uptime // 3600)
                    minutes = int((uptime % 3600) // 60)
                    uptime_str = f"{hours}小时{minutes}分钟"
                status_text.append(f"运行时间: {uptime_str}")

            connector_status = status.get('connector_status', {})
            if connector_status:
                status_text.append(f"Worker ID: {connector_status.get('worker_id', '未知')}")
                status_text.append(f"已注册: {'是' if connector_status.get('is_registered') else '否'}")
                status_text.append(f"当前任务: {connector_status.get('current_task_count', 0)}/{connector_status.get('max_concurrent_tasks', 0)}")

            stats = status.get('stats', {})
            if stats:
                status_text.append(f"接收任务: {stats.get('tasks_received', 0)}")
                status_text.append(f"完成任务: {stats.get('tasks_completed', 0)}")
                status_text.append(f"失败任务: {stats.get('tasks_failed', 0)}")

            messagebox.showinfo("Worker详细状态", "\n".join(status_text))

        except Exception as e:
            messagebox.showerror("错误", f"获取Worker状态时发生错误:\n{str(e)}")

    def test_worker_connection(self):
        """测试Worker连接"""
        if not self.config.is_worker_enabled():
            messagebox.showerror("错误", "Worker功能未启用\n请先在配置页面启用Worker模式")
            return

        def test_worker_in_thread():
            try:
                from test_worker_integration import WorkerIntegrationTester

                tester = WorkerIntegrationTester()
                result = tester.test_network_connectivity()

                if result.get("success"):
                    message = "Worker连接测试成功"
                    if result.get("details"):
                        message += "\n\n详情:\n" + "\n".join(result["details"])
                    self.parent.after(0, lambda: messagebox.showinfo("连接测试", message))
                else:
                    message = f"Worker连接测试失败:\n{result.get('message', '未知错误')}"
                    if result.get("details"):
                        message += "\n\n详情:\n" + "\n".join(result["details"])
                    self.parent.after(0, lambda: messagebox.showerror("连接测试", message))

            except Exception as e:
                error_msg = f"测试Worker连接时发生错误:\n{str(e)}"
                self.parent.after(0, lambda: messagebox.showerror("错误", error_msg))

        threading.Thread(target=test_worker_in_thread, daemon=True).start()

    def _worker_monitor_thread(self):
        """Worker监控线程"""
        while self.worker_client and hasattr(self.worker_client, 'is_running') and self.worker_client.is_running:
            try:
                # 更新Worker状态显示
                self.parent.after(0, self._update_worker_status_display)
                time.sleep(5)  # 每5秒更新一次
            except Exception as e:
                self.logger.error(f"Worker监控线程异常: {e}")
                break

        # Worker停止后清理状态显示
        self.parent.after(0, self._clear_worker_status_display)

    def _update_worker_status_display(self):
        """更新Worker状态显示"""
        try:
            if not self.worker_client:
                return

            status = self.worker_client.get_status()
            worker_config = self.config.get_worker_config()

            # 更新状态标签
            if status.get('is_running'):
                self.worker_status_label.configure(text="● Worker运行中", foreground="green")

                connector_status = status.get('connector_status', {})
                if connector_status.get('is_registered'):
                    detail = f"已注册到调度系统"
                else:
                    detail = f"未注册到调度系统"

                self.worker_detail_label.configure(text=detail)

                # 更新Worker信息 - 优先显示运行时的真实Worker ID
                real_worker_id = connector_status.get('worker_id')
                if real_worker_id:
                    self.worker_id_label.configure(text=real_worker_id)
                else:
                    # 回退到配置的Worker ID
                    self.worker_id_label.configure(text=worker_config.get('id', '-'))
                current_tasks = connector_status.get('current_task_count', 0)
                max_tasks = connector_status.get('max_concurrent_tasks', 0)
                self.worker_tasks_label.configure(text=f"{current_tasks}/{max_tasks}")
                self.worker_api_label.configure(text=worker_config.get('api_base', '-'))

            else:
                self.worker_status_label.configure(text="● Worker已停止", foreground="red")
                self.worker_detail_label.configure(text="")

        except Exception as e:
            self.logger.error(f"更新Worker状态显示异常: {e}")

    def _clear_worker_status_display(self):
        """清理Worker状态显示"""
        self.worker_status_label.configure(text="● Worker未启动", foreground="gray")
        self.worker_detail_label.configure(text="")
        self.worker_id_label.configure(text="-")
        self.worker_tasks_label.configure(text="-")
        self.worker_api_label.configure(text="-")
        # 更新按钮状态
        self.start_worker_button.configure(state=tk.NORMAL)
        self.stop_worker_button.configure(state=tk.DISABLED)





    def on_status_change(self, status, details):
        """状态变化回调"""
        self.parent.after(0, lambda: self.update_status_display(status, details))

    def update_status_display(self, status, details):
        """更新状态显示"""
        status_colors = {
            "stopped": ("● 已停止", "red"),
            "starting": ("● 启动中", "orange"),
            "running": ("● 运行中", "green"),
            "stopping": ("● 停止中", "orange")
        }

        if status in status_colors:
            text, color = status_colors[status]
            self.status_label.configure(text=text, foreground=color)

        # 更新详细信息
        message = details.get("message", "")
        if details.get("pid"):
            message += f" (PID: {details['pid']})"

        self.detail_label.configure(text=message)

    def update_status(self):
        """更新状态"""
        status_info = self.service_controller.get_service_status()

        # 更新状态指示
        self.update_status_display(status_info["status"], {"message": ""})

        # 更新服务信息
        service_config = self.config.get_service_config()
        host = service_config.get('host', '0.0.0.0')
        port = service_config.get('port', 5000)

        if host == '0.0.0.0':
            host = 'localhost'

        self.address_label.configure(text=f"http://{host}:{port}")
        self.pid_label.configure(text=str(status_info["pid"]) if status_info["pid"] else "-")

        # 运行时间
        if status_info["uptime"]:
            uptime_str = f"{int(status_info['uptime'] // 60)}分{int(status_info['uptime'] % 60)}秒"
            self.uptime_label.configure(text=uptime_str)
        else:
            self.uptime_label.configure(text="-")

        # 更新按钮状态
        running = status_info["running"]
        self.start_button.configure(state=tk.DISABLED if running else tk.NORMAL)
        self.stop_button.configure(state=tk.NORMAL if running else tk.DISABLED)
        self.restart_button.configure(state=tk.NORMAL if running else tk.DISABLED)

    def update_status_safe(self):
        """安全的状态更新（避免阻塞）"""
        try:
            # 使用快速检查，避免网络调用
            status_info = self.service_controller.get_service_status_fast()

            # 只更新基本状态，避免复杂操作
            self.update_status_display(status_info["status"], {"message": ""})

            # 更新服务信息
            service_config = self.config.get_service_config()
            host = service_config.get('host', '0.0.0.0')
            port = service_config.get('port', 5000)

            if host == '0.0.0.0':
                host = 'localhost'

            self.address_label.configure(text=f"http://{host}:{port}")
            self.pid_label.configure(text=str(status_info["pid"]) if status_info["pid"] else "-")

            # 运行时间
            if status_info["uptime"]:
                uptime_str = f"{int(status_info['uptime'] // 60)}分{int(status_info['uptime'] % 60)}秒"
                self.uptime_label.configure(text=uptime_str)
            else:
                self.uptime_label.configure(text="-")

            # 更新按钮状态
            running = status_info["running"]
            self.start_button.configure(state=tk.DISABLED if running else tk.NORMAL)
            self.stop_button.configure(state=tk.NORMAL if running else tk.DISABLED)
            self.restart_button.configure(state=tk.NORMAL if running else tk.DISABLED)

        except Exception as e:
            # 静默处理错误，避免影响服务运行
            self.logger.debug(f"状态更新异常（静默处理）: {e}")
            pass

    def start_status_update_thread(self):
        """启动状态更新线程（智能更新频率）"""
        def update_loop():
            consecutive_same_status = 0
            last_status = None

            while True:
                try:
                    # 获取当前状态
                    current_status = None
                    if hasattr(self.service_controller, 'service_status'):
                        current_status = self.service_controller.service_status

                    # 根据状态调整更新频率
                    if current_status in ["starting", "stopping"]:
                        # 状态变化期间，更频繁更新
                        update_interval = 2
                    elif current_status == last_status:
                        # 状态稳定时，逐渐降低更新频率
                        consecutive_same_status += 1
                        if consecutive_same_status < 3:
                            update_interval = 5
                        elif consecutive_same_status < 10:
                            update_interval = 15
                        else:
                            update_interval = 60  # 最长60秒
                    else:
                        # 状态发生变化，重置计数器
                        consecutive_same_status = 0
                        update_interval = 2

                    last_status = current_status

                    # 使用非阻塞方式更新状态
                    try:
                        self.parent.after(0, self.update_status_safe)
                        # 同时更新任务列表（如果API服务或Worker在运行）
                        if hasattr(self, 'task_tree'):
                            # 检查API服务或Worker是否在运行
                            api_running = current_status == "running"
                            worker_running = (hasattr(self, 'worker_client') and
                                            self.worker_client and
                                            hasattr(self.worker_client, 'is_running') and
                                            self.worker_client.is_running)

                            if api_running or worker_running:
                                self.parent.after(0, self.update_task_list)
                    except:
                        pass

                    # 动态更新间隔
                    threading.Event().wait(update_interval)

                except Exception as e:
                    self.logger.debug(f"状态更新线程异常: {e}")
                    threading.Event().wait(30)
                    break

        # 启动状态更新线程
        thread = threading.Thread(target=update_loop, daemon=True)
        thread.start()

    def create_task_management_ui(self, parent):
        """创建任务管理界面"""
        # 任务列表框架
        task_frame = ttk.LabelFrame(parent, text="任务列表", padding=10)
        task_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))

        # 控制面板
        control_panel = ttk.Frame(task_frame)
        control_panel.pack(fill=tk.X, pady=(0, 10))

        # 任务统计
        self.task_summary_label = ttk.Label(control_panel, text="任务统计: 总计0个")
        self.task_summary_label.pack(side=tk.LEFT)

        # 控制按钮
        button_frame = ttk.Frame(control_panel)
        button_frame.pack(side=tk.RIGHT)

        ttk.Button(button_frame, text="刷新", command=self.refresh_tasks).pack(side=tk.LEFT, padx=(0, 5))
        ttk.Button(button_frame, text="清理已完成", command=self.cleanup_tasks).pack(side=tk.LEFT, padx=(0, 5))

        # 任务列表表格
        list_frame = ttk.Frame(task_frame)
        list_frame.pack(fill=tk.BOTH, expand=True)

        # 定义列
        columns = ("task_id", "source", "status", "progress", "created_time", "duration")
        self.task_tree = ttk.Treeview(list_frame, columns=columns, show="headings", height=12)

        # 设置列标题和宽度
        self.task_tree.heading("task_id", text="任务ID")
        self.task_tree.heading("source", text="来源")
        self.task_tree.heading("status", text="状态")
        self.task_tree.heading("progress", text="进度")
        self.task_tree.heading("created_time", text="创建时间")
        self.task_tree.heading("duration", text="耗时")

        self.task_tree.column("task_id", width=120, minwidth=100)
        self.task_tree.column("source", width=100, minwidth=80)
        self.task_tree.column("status", width=80, minwidth=60)
        self.task_tree.column("progress", width=120, minwidth=100)
        self.task_tree.column("created_time", width=140, minwidth=120)
        self.task_tree.column("duration", width=80, minwidth=60)

        # 滚动条
        v_scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.task_tree.yview)
        self.task_tree.configure(yscrollcommand=v_scrollbar.set)

        h_scrollbar = ttk.Scrollbar(list_frame, orient=tk.HORIZONTAL, command=self.task_tree.xview)
        self.task_tree.configure(xscrollcommand=h_scrollbar.set)

        # 布局
        self.task_tree.grid(row=0, column=0, sticky=tk.NSEW)
        v_scrollbar.grid(row=0, column=1, sticky=tk.NS)
        h_scrollbar.grid(row=1, column=0, sticky=tk.EW)

        list_frame.grid_rowconfigure(0, weight=1)
        list_frame.grid_columnconfigure(0, weight=1)

        # 右键菜单
        self.create_task_context_menu()

        # 绑定事件
        self.task_tree.bind("<Button-3>", self.show_task_context_menu)  # 右键
        self.task_tree.bind("<Double-1>", self.show_task_details)  # 双击

        # 初始化任务数据
        self.task_data = {}

    def create_task_context_menu(self):
        """创建任务右键菜单"""
        self.task_context_menu = tk.Menu(self.parent, tearoff=0)
        self.task_context_menu.add_command(label="查看详情", command=self.show_task_details)
        self.task_context_menu.add_command(label="取消任务", command=self.cancel_selected_task)
        self.task_context_menu.add_separator()
        self.task_context_menu.add_command(label="复制任务ID", command=self.copy_task_id)
        self.task_context_menu.add_command(label="刷新", command=self.refresh_tasks)

    def show_task_context_menu(self, event):
        """显示任务右键菜单"""
        # 选中右键点击的项目
        item = self.task_tree.identify_row(event.y)
        if item:
            self.task_tree.selection_set(item)
            self.task_context_menu.post(event.x_root, event.y_root)

    def show_task_details(self, event=None):
        """显示任务详情"""
        selection = self.task_tree.selection()
        if not selection:
            return

        task_id = self.task_tree.item(selection[0])['values'][0]
        if task_id in self.task_data:
            self.open_task_detail_dialog(task_id, self.task_data[task_id])

    def open_task_detail_dialog(self, task_id, task_data):
        """打开任务详情对话框"""
        dialog = tk.Toplevel(self.parent)
        dialog.title(f"任务详情 - {task_id}")
        dialog.geometry("600x500")
        dialog.resizable(True, True)

        # 使对话框模态
        dialog.transient(self.parent)
        dialog.grab_set()

        # 任务基本信息
        info_frame = ttk.LabelFrame(dialog, text="基本信息", padding=10)
        info_frame.pack(fill=tk.X, padx=10, pady=5)

        info_text = f"""任务ID: {task_id}
任务类型: {task_data.get('task_type_name', 'N/A')}
状态: {task_data.get('status_name', 'N/A')}
创建时间: {task_data.get('created_time', 'N/A')}
开始时间: {task_data.get('start_time', 'N/A')}
结束时间: {task_data.get('end_time', 'N/A')}
耗时: {task_data.get('duration_text', 'N/A')}"""

        ttk.Label(info_frame, text=info_text, justify=tk.LEFT).pack(anchor=tk.W)

        # 进度信息
        progress_frame = ttk.LabelFrame(dialog, text="执行进度", padding=10)
        progress_frame.pack(fill=tk.X, padx=10, pady=5)

        progress = task_data.get('progress', {})
        stages = progress.get('stages', {})

        for stage_id, stage_info in stages.items():
            stage_text = f"● {stage_info.get('name', stage_id)}: {stage_info.get('status', 'pending')}"
            label = ttk.Label(progress_frame, text=stage_text)
            label.pack(anchor=tk.W)

        # 参数信息
        params_frame = ttk.LabelFrame(dialog, text="任务参数", padding=10)
        params_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

        params_text = scrolledtext.ScrolledText(params_frame, height=8, wrap=tk.WORD)
        params_text.pack(fill=tk.BOTH, expand=True)

        # 显示参数
        display_params = task_data.get('display_params', {})
        for key, value in display_params.items():
            params_text.insert(tk.END, f"{key}: {value}\n")

        # 如果有错误信息，显示错误
        if task_data.get('error'):
            params_text.insert(tk.END, f"\n错误信息: {task_data['error']}\n")

        params_text.config(state=tk.DISABLED)

        # 按钮
        button_frame = ttk.Frame(dialog)
        button_frame.pack(fill=tk.X, padx=10, pady=5)

        ttk.Button(button_frame, text="关闭", command=dialog.destroy).pack(side=tk.RIGHT)

    def cancel_selected_task(self):
        """取消选中的任务"""
        selection = self.task_tree.selection()
        if not selection:
            return

        task_id = self.task_tree.item(selection[0])['values'][0]
        self.cancel_task(task_id)

    def copy_task_id(self):
        """复制任务ID到剪贴板"""
        selection = self.task_tree.selection()
        if not selection:
            return

        task_id = self.task_tree.item(selection[0])['values'][0]
        self.parent.clipboard_clear()
        self.parent.clipboard_append(task_id)

    def refresh_tasks(self):
        """刷新任务列表"""
        self.update_task_list()

    def cleanup_tasks(self):
        """清理已完成的任务"""
        if messagebox.askyesno("确认", "确定要清理所有已完成的任务吗？"):
            try:
                # 调用API清理任务
                self.call_api_cleanup_tasks()
                self.update_task_list()
                messagebox.showinfo("成功", "已完成任务清理成功！")
            except Exception as e:
                messagebox.showerror("错误", f"清理任务失败: {str(e)}")

    def call_api_cleanup_tasks(self):
        """调用API清理任务"""
        import requests
        service_config = self.config.get_service_config()
        port = service_config.get('port', 5000)

        response = requests.post(f"http://localhost:{port}/api/cleanup", timeout=10)
        if response.status_code != 200:
            raise Exception(f"API调用失败: {response.status_code}")

    def cancel_task(self, task_id):
        """取消指定任务"""
        try:
            import requests
            service_config = self.config.get_service_config()
            port = service_config.get('port', 5000)

            response = requests.post(f"http://localhost:{port}/api/cancel-task/{task_id}", timeout=5)
            if response.status_code == 200:
                messagebox.showinfo("成功", f"任务 {task_id} 已取消")
                self.update_task_list()
            else:
                messagebox.showerror("失败", f"取消任务失败: {response.status_code}")
        except Exception as e:
            messagebox.showerror("错误", f"取消任务失败: {str(e)}")

    def update_task_list(self):
        """更新任务列表"""
        try:
            # 获取TaskDispatcher实例并获取任务列表
            task_data = self._get_unified_task_list()

            # 检查是否获取到数据
            if task_data is None:
                # 获取任务失败
                for item in self.task_tree.get_children():
                    self.task_tree.delete(item)
                self.task_summary_label.config(text="任务统计: 获取失败，请查看日志")
                self.logger.error("无法获取任务列表")
                return

            # 检查API和Worker的运行状态
            api_running = task_data.get('api_running', False)
            worker_running = task_data.get('worker_running', False)
            tasks = task_data.get('tasks', {})
            summary = task_data.get('summary', {})

            # 更新任务数据
            self.task_data = tasks

            # 清空现有列表
            for item in self.task_tree.get_children():
                self.task_tree.delete(item)

            # 填充任务列表
            for task_id, task_info in tasks.items():
                # 格式化显示数据
                source = self._format_task_source(task_info.get('source', 'unknown'))
                status = task_info.get('status', 'unknown')
                progress = self._format_progress_simple(task_info)
                created_time = self._format_time(task_info.get('created_time', task_info.get('timestamp')))
                duration = self._format_duration(task_info)

                # 插入到表格
                self.task_tree.insert("", tk.END, values=(
                    task_id, source, status, progress, created_time, duration
                ))

            # 更新统计信息
            total = summary.get('total', 0)
            pending = summary.get('pending', 0)
            running = summary.get('running', 0)
            completed = summary.get('completed', 0)
            failed = summary.get('failed', 0)

            # 根据API和Worker运行状态显示不同的提示
            status_parts = []
            if api_running:
                status_parts.append("API")
            if worker_running:
                status_parts.append("Worker")

            if not api_running and not worker_running:
                summary_text = f"任务统计: API和Worker都未运行 - 总计{total}个任务"
            elif status_parts:
                sources = "+".join(status_parts)
                summary_text = f"任务统计: {sources} - 总计{total}个 (等待{pending}, 运行{running}, 完成{completed}, 失败{failed})"
            else:
                summary_text = f"任务统计: 总计{total}个 (等待{pending}, 运行{running}, 完成{completed}, 失败{failed})"

            self.task_summary_label.config(text=summary_text)

        except Exception as e:
            self.logger.error(f"更新任务列表失败: {e}")
            import traceback
            self.logger.error(f"异常详情: {traceback.format_exc()}")
            self.task_summary_label.config(text="任务统计: 更新失败，请查看日志")

    def _get_unified_task_list(self):
        """获取统一的任务列表（从API服务和Worker两个来源）"""
        try:
            all_tasks = {}
            api_tasks_fetched = False
            worker_tasks_fetched = False

            # 来源1: 尝试从API服务获取任务（HTTP API接收的任务）
            if self.service_controller.is_service_running_fast():
                api_tasks = self._get_tasks_from_api()
                if api_tasks is not None:  # 注意：空字典{}也是成功的
                    all_tasks.update(api_tasks)
                    api_tasks_fetched = True
                    self.logger.debug(f"从API服务获取到 {len(api_tasks)} 个任务")
            else:
                self.logger.info("API服务未运行，跳过API任务获取")

            # 来源2: 尝试从Worker客户端获取任务（Worker接收的远程任务）
            worker_tasks = self._get_tasks_from_worker()
            if worker_tasks is not None:  # 注意：空字典{}也是成功的
                all_tasks.update(worker_tasks)
                worker_tasks_fetched = True
                self.logger.debug(f"从Worker获取到 {len(worker_tasks)} 个任务")

            # 如果两个来源都没获取到任务
            if not api_tasks_fetched and not worker_tasks_fetched:
                self.logger.info("API服务和Worker都未运行，返回空任务列表")
                return {
                    'tasks': {},
                    'summary': {
                        'total': 0,
                        'pending': 0,
                        'running': 0,
                        'completed': 0,
                        'failed': 0
                    },
                    'api_running': False,
                    'worker_running': False
                }

            # 计算统计信息
            summary = {
                'total': len(all_tasks),
                'pending': len([t for t in all_tasks.values() if t.get('status') in ['pending', 'waiting']]),
                'running': len([t for t in all_tasks.values() if t.get('status') in ['running', 'processing']]),
                'completed': len([t for t in all_tasks.values() if t.get('status') == 'completed']),
                'failed': len([t for t in all_tasks.values() if t.get('status') == 'failed'])
            }

            return {
                'tasks': all_tasks,
                'summary': summary,
                'api_running': api_tasks_fetched,
                'worker_running': worker_tasks_fetched
            }

        except Exception as e:
            self.logger.error(f"获取统一任务列表失败: {e}")
            import traceback
            self.logger.error(f"异常详情: {traceback.format_exc()}")
            return None

    def _get_tasks_from_api(self):
        """从API服务获取任务"""
        try:
            import requests
            service_config = self.config.get_service_config()
            port = service_config.get('port', 5000)

            # 尝试调用新的统一任务列表接口
            try:
                self.logger.debug(f"请求API: http://localhost:{port}/api/unified-tasks")
                response = requests.get(f"http://localhost:{port}/api/unified-tasks", timeout=5)
                self.logger.debug(f"API响应状态码: {response.status_code}")

                if response.status_code == 200:
                    data = response.json()
                    if data.get('success'):
                        result_data = data.get('data', {})
                        tasks = result_data.get('tasks', {})
                        self.logger.debug(f"成功获取统一任务列表，任务数: {len(tasks)}")
                        return tasks
                    else:
                        self.logger.warning(f"API返回失败: {data.get('message', '未知错误')}")
                else:
                    self.logger.warning(f"API请求失败，状态码: {response.status_code}")

            except requests.exceptions.ConnectionError as e:
                self.logger.warning(f"连接API失败: {e}")
            except requests.exceptions.Timeout as e:
                self.logger.warning(f"API请求超时: {e}")
            except Exception as e:
                self.logger.warning(f"调用unified-tasks API异常: {e}")

            # 回退到原有接口
            try:
                self.logger.debug(f"回退到原有API: http://localhost:{port}/api/tasks")
                response = requests.get(f"http://localhost:{port}/api/tasks", timeout=5)
                self.logger.debug(f"API响应状态码: {response.status_code}")

                if response.status_code == 200:
                    data = response.json()
                    if data.get('success'):
                        # 转换旧格式数据，添加source字段
                        response_data = data.get('data', {})
                        if isinstance(response_data, dict) and 'tasks' in response_data:
                            # 新格式：包含tasks和summary
                            tasks = response_data['tasks']
                            for task_id, task_info in tasks.items():
                                if 'source' not in task_info:
                                    task_info['source'] = 'http_api'
                            self.logger.debug(f"成功获取任务列表，任务数: {len(tasks)}")
                            return tasks
                        else:
                            # 旧格式：直接是tasks字典
                            tasks = response_data
                            for task_id, task_info in tasks.items():
                                if 'source' not in task_info:
                                    task_info['source'] = 'http_api'
                            self.logger.debug(f"成功获取任务列表（旧格式），任务数: {len(tasks)}")
                            return tasks
                    else:
                        self.logger.warning(f"API返回失败: {data.get('message', '未知错误')}")
                else:
                    self.logger.warning(f"API请求失败，状态码: {response.status_code}")

            except requests.exceptions.ConnectionError as e:
                self.logger.warning(f"连接API失败: {e}")
            except requests.exceptions.Timeout as e:
                self.logger.warning(f"API请求超时: {e}")
            except Exception as e:
                self.logger.warning(f"调用tasks API异常: {e}")

            # 所有API调用都失败
            self.logger.warning("所有API接口调用都失败")
            return None

        except Exception as e:
            self.logger.error(f"从API获取任务失败: {e}")
            return None

    def _get_tasks_from_worker(self):
        """从Worker客户端获取任务"""
        try:
            # 检查是否有运行中的Worker客户端
            if not hasattr(self, 'worker_client') or not self.worker_client:
                self.logger.debug("Worker客户端未创建")
                return None

            worker_client = self.worker_client

            # 检查Worker是否运行
            if not hasattr(worker_client, 'is_running') or not worker_client.is_running:
                self.logger.debug("Worker未运行")
                return None

            # 检查Worker是否有task_dispatcher
            if not hasattr(worker_client, 'task_dispatcher') or not worker_client.task_dispatcher:
                self.logger.debug("Worker的task_dispatcher未初始化")
                return None

            # 从TaskDispatcher获取任务列表
            task_dispatcher = worker_client.task_dispatcher
            self.logger.debug("正在从Worker的TaskDispatcher获取任务...")
            task_data = task_dispatcher.list_tasks()

            if task_data and 'tasks' in task_data:
                tasks = task_data['tasks']
                self.logger.info(f"从Worker的TaskDispatcher获取到 {len(tasks)} 个任务")
                # 确保所有任务都标记了来源
                for task_id, task_info in tasks.items():
                    if 'source' not in task_info:
                        task_info['source'] = 'remote_scheduler'
                return tasks
            else:
                self.logger.debug("Worker的TaskDispatcher返回空任务列表")
                return {}  # 返回空字典而不是None，表示Worker运行但无任务

        except Exception as e:
            self.logger.error(f"从Worker获取任务失败: {e}")
            import traceback
            self.logger.error(f"异常详情: {traceback.format_exc()}")
            return None

    def _format_task_source(self, source):
        """格式化任务来源显示"""
        source_map = {
            'http_api': 'HTTP API',
            'remote_scheduler': 'Worker',
            'HTTP_API': 'HTTP API',
            'REMOTE_SCHEDULER': 'Worker'
        }
        return source_map.get(source, source)

    def _format_progress_simple(self, task_info):
        """简化的进度格式化"""
        if 'progress' in task_info:
            progress = task_info['progress']
            if isinstance(progress, dict):
                return f"{progress.get('percentage', 0)}%"
            elif isinstance(progress, (int, float)):
                return f"{progress}%"
        return "0%"

    def _format_time(self, time_str):
        """格式化时间显示"""
        if not time_str or time_str == 'N/A':
            return 'N/A'

        try:
            # 处理ISO格式时间
            if 'T' in str(time_str):
                return str(time_str).split('T')[1][:8]  # 只显示时间部分 HH:MM:SS
            else:
                return str(time_str)[:19]  # 显示日期和时间
        except:
            return str(time_str)[:19]

    def _format_duration(self, task_info):
        """格式化持续时间"""
        if 'duration_text' in task_info:
            return task_info['duration_text']
        elif 'duration' in task_info:
            duration = task_info['duration']
            if isinstance(duration, (int, float)) and duration > 0:
                return f"{duration:.1f}s"
        return "N/A"

    def format_progress(self, progress):
        """格式化进度显示"""
        current_stage = progress.get('current_stage', 'unknown')
        stages = progress.get('stages', {})

        if current_stage == 'unknown':
            return 'N/A'
        elif current_stage == 'cancelled':
            return '已取消'

        stage_names = {
            'downloading': '剪映小助手',
            'exporting': '剪映导出',
            'uploading': 'OSS上传',
            'finished': '完成'
        }

        return stage_names.get(current_stage, current_stage)

    def format_params(self, params):
        """格式化参数显示"""
        if not params:
            return 'N/A'

        parts = []
        if 'draft_name' in params:
            parts.append(f"草稿: {params['draft_name']}")
        if 'url' in params:
            parts.append(f"URL: {params['url']}")

        return "; ".join(parts) if parts else 'N/A'


class LogTab:
    """日志选项卡"""

    def __init__(self, parent, config_manager):
        self.parent = parent
        self.config = config_manager
        self.log_viewer = LogViewer()

        self.create_widgets()
        self.setup_log_viewer()

    def create_widgets(self):
        """创建界面控件"""
        # 主框架
        main_frame = ttk.Frame(self.parent)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 控制面板
        control_frame = ttk.Frame(main_frame)
        control_frame.pack(fill=tk.X, pady=(0, 10))

        # 日志级别过滤
        ttk.Label(control_frame, text="日志级别:").pack(side=tk.LEFT, padx=(0, 5))

        self.level_vars = {}
        for level in LogLevel.ALL_LEVELS:
            var = tk.BooleanVar(value=True)
            self.level_vars[level] = var
            ttk.Checkbutton(control_frame, text=level, variable=var,
                           command=self.update_filter).pack(side=tk.LEFT, padx=(0, 10))

        # 文本搜索
        ttk.Label(control_frame, text="搜索:").pack(side=tk.LEFT, padx=(20, 5))
        self.search_var = tk.StringVar()
        search_entry = ttk.Entry(control_frame, textvariable=self.search_var, width=20)
        search_entry.pack(side=tk.LEFT, padx=(0, 5))
        search_entry.bind('<KeyRelease>', self.on_search_change)

        ttk.Button(control_frame, text="清空日志", command=self.clear_logs).pack(side=tk.RIGHT, padx=(10, 0))
        ttk.Button(control_frame, text="导出日志", command=self.export_logs).pack(side=tk.RIGHT, padx=(10, 0))
        ttk.Button(control_frame, text="刷新", command=self.refresh_logs).pack(side=tk.RIGHT, padx=(10, 0))

        # 日志显示区域
        log_frame = ttk.Frame(main_frame)
        log_frame.pack(fill=tk.BOTH, expand=True)

        # 创建Treeview显示日志
        columns = ("时间", "级别", "模块", "消息")
        self.log_tree = ttk.Treeview(log_frame, columns=columns, show="headings", height=20)

        # 设置列
        self.log_tree.heading("时间", text="时间")
        self.log_tree.heading("级别", text="级别")
        self.log_tree.heading("模块", text="模块")
        self.log_tree.heading("消息", text="消息")

        self.log_tree.column("时间", width=150, minwidth=150)
        self.log_tree.column("级别", width=80, minwidth=80)
        self.log_tree.column("模块", width=120, minwidth=120)
        self.log_tree.column("消息", width=600, minwidth=300)  # 增加消息列宽度

        # 绑定事件
        self.log_tree.bind("<Button-3>", self.show_context_menu)  # 右键菜单
        self.log_tree.bind("<Double-1>", self.show_log_detail)    # 双击查看详情

        # 滚动条
        v_scrollbar = ttk.Scrollbar(log_frame, orient=tk.VERTICAL, command=self.log_tree.yview)
        self.log_tree.configure(yscrollcommand=v_scrollbar.set)

        h_scrollbar = ttk.Scrollbar(log_frame, orient=tk.HORIZONTAL, command=self.log_tree.xview)
        self.log_tree.configure(xscrollcommand=h_scrollbar.set)

        # 布局
        self.log_tree.grid(row=0, column=0, sticky=tk.NSEW)
        v_scrollbar.grid(row=0, column=1, sticky=tk.NS)
        h_scrollbar.grid(row=1, column=0, sticky=tk.EW)

        log_frame.grid_rowconfigure(0, weight=1)
        log_frame.grid_columnconfigure(0, weight=1)

        # 状态栏
        self.status_label = ttk.Label(main_frame, text="就绪")
        self.status_label.pack(side=tk.BOTTOM, fill=tk.X, pady=(5, 0))

    def setup_log_viewer(self):
        """设置日志查看器"""
        # 设置新日志回调
        self.log_viewer.set_new_log_callback(self.on_new_log)

        # 开始监控（如果有日志文件）
        # 这里可以添加日志文件路径
        # self.log_viewer.add_log_file("service.log")
        # self.log_viewer.start_monitoring()

    def on_new_log(self, log_entry):
        """新日志回调"""
        self.parent.after(0, lambda: self.add_log_to_tree(log_entry))

    def add_log_to_tree(self, log_entry):
        """添加日志到树形控件"""
        # 设置级别颜色
        level_colors = {
            "DEBUG": "gray",
            "INFO": "black",
            "WARNING": "orange",
            "ERROR": "red",
            "CRITICAL": "darkred"
        }

        color = level_colors.get(log_entry.level, "black")

        # 插入日志
        item = self.log_tree.insert("", tk.END, values=(
            log_entry.timestamp,
            log_entry.level,
            log_entry.logger,
            log_entry.message
        ))

        # 设置颜色（如果支持）
        try:
            self.log_tree.set(item, "级别", log_entry.level)
        except:
            pass

        # 自动滚动到底部
        self.log_tree.see(item)

        # 限制显示的日志数量
        items = self.log_tree.get_children()
        if len(items) > 1000:
            self.log_tree.delete(items[0])

    def update_filter(self):
        """更新过滤器"""
        # 获取选中的级别
        selected_levels = [level for level, var in self.level_vars.items() if var.get()]
        self.log_viewer.set_level_filter(selected_levels)
        self.refresh_logs()

    def on_search_change(self, event):
        """搜索文本变化"""
        search_text = self.search_var.get()
        self.log_viewer.set_text_filter(search_text)
        self.refresh_logs()

    def refresh_logs(self):
        """刷新日志显示"""
        # 清空现有显示
        for item in self.log_tree.get_children():
            self.log_tree.delete(item)

        # 获取过滤后的日志
        filtered_logs = self.log_viewer.get_filtered_logs(limit=1000)

        # 添加到树形控件
        for log_entry in filtered_logs:
            self.add_log_to_tree(log_entry)

        # 更新状态
        total_logs = len(self.log_viewer.log_entries)
        filtered_count = len(filtered_logs)
        self.status_label.configure(text=f"显示 {filtered_count}/{total_logs} 条日志")

    def clear_logs(self):
        """清空日志"""
        if messagebox.askyesno("确认", "确定要清空所有日志吗？"):
            self.log_viewer.clear_logs()
            for item in self.log_tree.get_children():
                self.log_tree.delete(item)
            self.status_label.configure(text="日志已清空")

    def export_logs(self):
        """导出日志"""
        file_path = filedialog.asksaveasfilename(
            title="导出日志",
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )

        if file_path:
            if self.log_viewer.export_logs(file_path, filtered=True):
                messagebox.showinfo("成功", f"日志已导出到: {file_path}")
            else:
                messagebox.showerror("失败", "导出日志失败")

    def show_context_menu(self, event):
        """显示右键菜单"""
        # 选择点击的项目
        item = self.log_tree.identify_row(event.y)
        if item:
            self.log_tree.selection_set(item)

            # 创建右键菜单
            context_menu = tk.Menu(self.parent, tearoff=0)
            context_menu.add_command(label="复制消息", command=self.copy_log_message)
            context_menu.add_command(label="复制完整日志", command=self.copy_full_log)
            context_menu.add_separator()
            context_menu.add_command(label="查看详情", command=self.show_log_detail)

            try:
                context_menu.tk_popup(event.x_root, event.y_root)
            finally:
                context_menu.grab_release()

    def copy_log_message(self):
        """复制日志消息到剪贴板"""
        selection = self.log_tree.selection()
        if selection:
            item = selection[0]
            values = self.log_tree.item(item, "values")
            if len(values) >= 4:
                message = values[3]  # 消息列
                self.parent.clipboard_clear()
                self.parent.clipboard_append(message)
                self.status_label.configure(text="消息已复制到剪贴板")

    def copy_full_log(self):
        """复制完整日志行到剪贴板"""
        selection = self.log_tree.selection()
        if selection:
            item = selection[0]
            values = self.log_tree.item(item, "values")
            if len(values) >= 4:
                full_log = f"[{values[0]}] {values[1]} - {values[2]} - {values[3]}"
                self.parent.clipboard_clear()
                self.parent.clipboard_append(full_log)
                self.status_label.configure(text="完整日志已复制到剪贴板")

    def show_log_detail(self, event=None):
        """显示日志详情对话框"""
        selection = self.log_tree.selection()
        if selection:
            item = selection[0]
            values = self.log_tree.item(item, "values")
            if len(values) >= 4:
                self.open_log_detail_dialog(values)

    def open_log_detail_dialog(self, log_values):
        """打开日志详情对话框"""
        dialog = tk.Toplevel(self.parent)
        dialog.title("日志详情")
        dialog.geometry("800x500")
        dialog.resizable(True, True)

        # 设置对话框图标和属性
        dialog.transient(self.parent)
        dialog.grab_set()

        # 创建主框架
        main_frame = ttk.Frame(dialog, padding=10)
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 基本信息框架
        info_frame = ttk.LabelFrame(main_frame, text="基本信息", padding=10)
        info_frame.pack(fill=tk.X, pady=(0, 10))

        # 显示基本信息
        ttk.Label(info_frame, text="时间:").grid(row=0, column=0, sticky=tk.W, padx=(0, 10))
        ttk.Label(info_frame, text=log_values[0]).grid(row=0, column=1, sticky=tk.W)

        ttk.Label(info_frame, text="级别:").grid(row=1, column=0, sticky=tk.W, padx=(0, 10))
        ttk.Label(info_frame, text=log_values[1]).grid(row=1, column=1, sticky=tk.W)

        ttk.Label(info_frame, text="模块:").grid(row=2, column=0, sticky=tk.W, padx=(0, 10))
        ttk.Label(info_frame, text=log_values[2]).grid(row=2, column=1, sticky=tk.W)

        # 消息内容框架
        message_frame = ttk.LabelFrame(main_frame, text="消息内容", padding=10)
        message_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))

        # 消息文本框（支持滚动）
        message_text = scrolledtext.ScrolledText(
            message_frame,
            wrap=tk.WORD,
            height=15,
            font=("Consolas", 10)
        )
        message_text.pack(fill=tk.BOTH, expand=True)
        message_text.insert(tk.END, log_values[3])
        message_text.configure(state=tk.DISABLED)  # 只读

        # 按钮框架
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X)

        # 复制按钮
        def copy_message_content():
            dialog.clipboard_clear()
            dialog.clipboard_append(log_values[3])
            messagebox.showinfo("复制成功", "消息内容已复制到剪贴板")

        def copy_full_content():
            full_content = f"时间: {log_values[0]}\n级别: {log_values[1]}\n模块: {log_values[2]}\n\n消息:\n{log_values[3]}"
            dialog.clipboard_clear()
            dialog.clipboard_append(full_content)
            messagebox.showinfo("复制成功", "完整内容已复制到剪贴板")

        ttk.Button(button_frame, text="复制消息", command=copy_message_content).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(button_frame, text="复制全部", command=copy_full_content).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Button(button_frame, text="关闭", command=dialog.destroy).pack(side=tk.RIGHT)


class MainApplication:
    """主应用程序"""

    def __init__(self):
        self.root = tk.Tk()
        self.config = get_config()

        self.setup_window()
        self.create_widgets()

        # 设置日志
        self.setup_logging()

    def setup_window(self):
        """设置窗口"""
        self.root.title("剪映草稿自动化管理界面")
        self.root.geometry("900x700")
        self.root.minsize(800, 600)

        # 设置窗口关闭协议
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

        # 设置图标（如果有的话）
        try:
            # self.root.iconbitmap("icon.ico")
            pass
        except:
            pass

    def create_widgets(self):
        """创建界面控件"""
        # 创建笔记本控件（选项卡容器）
        notebook = ttk.Notebook(self.root)
        notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        # 配置选项卡
        config_frame = ttk.Frame(notebook)
        notebook.add(config_frame, text="配置")
        self.config_tab = ConfigTab(config_frame, self.config)

        # 服务选项卡
        service_frame = ttk.Frame(notebook)
        notebook.add(service_frame, text="服务")
        self.service_tab = ServiceTab(service_frame, self.config)

        # 日志选项卡
        log_frame = ttk.Frame(notebook)
        notebook.add(log_frame, text="日志")
        self.log_tab = LogTab(log_frame, self.config)

        # 关于选项卡
        about_frame = ttk.Frame(notebook)
        notebook.add(about_frame, text="关于")
        self.create_about_tab(about_frame)

        # 状态栏
        self.status_bar = ttk.Label(self.root, text="就绪", relief=tk.SUNKEN)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

    def create_about_tab(self, parent):
        """创建关于选项卡"""
        about_frame = ttk.Frame(parent)
        about_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

        # 标题
        title_label = ttk.Label(about_frame, text="剪映草稿自动化系统",
                               font=("Arial", 16, "bold"))
        title_label.pack(pady=(0, 20))

        # 功能介绍
        features_text = """
功能特点：
• 自动从URL提取草稿名称
• 支持剪映小助手自动下载
• 智能重试机制，处理下载失败
• 自动导出到指定路径
• 支持阿里云OSS自动上传
• 可视化配置管理
• 实时服务状态监控
• 详细日志查看和过滤

技术架构：
• Python + Tkinter GUI界面
• Flask HTTP API服务
• pyJianYingDraft核心库
• 阿里云OSS存储集成
• Windows UI自动化

使用流程：
1. 配置默认输出路径和OSS信息
2. 启动API服务
3. 通过API调用处理剪映草稿
4. 自动下载、导出、上传到云端
        """

        features_label = ttk.Label(about_frame, text=features_text, justify=tk.LEFT)
        features_label.pack(anchor=tk.W)

        # 版本信息
        version_frame = ttk.Frame(about_frame)
        version_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=(20, 0))

        ttk.Label(version_frame, text="版本: 1.0.0").pack(side=tk.LEFT)
        ttk.Label(version_frame, text="© 2025 剪映草稿自动化").pack(side=tk.RIGHT)

    def setup_logging(self):
        """设置日志"""
        # 创建日志处理器，将日志发送到GUI
        class GUILogHandler(logging.Handler):
            def __init__(self, log_viewer):
                super().__init__()
                self.log_viewer = log_viewer

            def emit(self, record):
                try:
                    log_line = self.format(record)
                    self.log_viewer.add_log_line(log_line)
                except:
                    pass

        # 添加GUI日志处理器
        gui_handler = GUILogHandler(self.log_tab.log_viewer)
        gui_handler.setFormatter(logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        ))

        # 添加到根日志器
        root_logger = logging.getLogger()
        root_logger.addHandler(gui_handler)
        root_logger.setLevel(logging.INFO)

        # 测试日志
        logging.info("GUI应用程序启动")

    def on_closing(self):
        """处理窗口关闭事件"""
        try:
            logging.info("关闭GUI应用程序...")

            # 先销毁窗口，让界面立即消失
            self.root.quit()
            self.root.destroy()

            # 在后台线程快速清理，避免阻塞
            import threading
            cleanup_thread = threading.Thread(target=self._quick_cleanup, daemon=True)
            cleanup_thread.start()

            # 等待最多1秒进行清理
            cleanup_thread.join(timeout=1.0)

            # 强制退出程序
            import sys
            import os
            os._exit(0)  # 使用os._exit直接退出，不等待线程

        except Exception as e:
            logging.error(f"关闭窗口时发生错误: {e}")
            # 即使出错也要强制退出
            import sys
            import os
            os._exit(1)

    def run(self):
        """运行应用程序"""
        try:
            self.root.mainloop()
        except KeyboardInterrupt:
            self.on_closing()
        except Exception as e:
            logging.error(f"GUI运行异常: {e}")
            self.on_closing()

    def _quick_cleanup(self):
        """快速清理资源（在后台线程中运行，有超时限制）"""
        try:
            # 设置监控标志为False，让监控线程自然退出
            if hasattr(self, 'service_tab') and self.service_tab:
                if hasattr(self.service_tab, 'service_controller'):
                    try:
                        self.service_tab.service_controller.monitoring = False
                    except:
                        pass

            # 不等待Worker停止，让它自然结束
            # 所有线程都是daemon线程，程序退出时会自动清理

        except Exception as e:
            logging.debug(f"快速清理异常（可忽略）: {e}")

    def cleanup(self):
        """清理资源"""
        try:
            logging.info("开始清理资源...")

            # 停止日志监控
            if hasattr(self, 'log_tab') and self.log_tab:
                try:
                    logging.info("停止日志监控...")
                    self.log_tab.log_viewer.stop_monitoring()
                except Exception as e:
                    logging.warning(f"停止日志监控失败: {e}")

            # 停止服务监控和Worker
            if hasattr(self, 'service_tab') and self.service_tab:
                try:
                    # 停止Worker客户端
                    if hasattr(self.service_tab, 'worker_client') and self.service_tab.worker_client:
                        try:
                            logging.info("停止Worker客户端...")
                            self.service_tab.worker_client.stop()
                        except Exception as e:
                            logging.warning(f"停止Worker客户端失败: {e}")

                    # 停止服务监控线程
                    if hasattr(self.service_tab, 'service_controller'):
                        try:
                            logging.info("停止服务监控...")
                            self.service_tab.service_controller._stop_monitoring()
                        except Exception as e:
                            logging.warning(f"停止服务监控失败: {e}")

                except Exception as e:
                    logging.warning(f"清理服务资源失败: {e}")

            logging.info("资源清理完成")

        except Exception as e:
            logging.error(f"清理资源时发生异常: {e}")
            # 即使出错也继续退出


def main():
    """主函数"""
    try:
        app = MainApplication()
        app.run()
    except Exception as e:
        print(f"应用程序启动失败: {e}")
        import traceback
        traceback.print_exc()


if __name__ == "__main__":
    main()